package com.bzkj.document.service.materialsoutbound.impl;

import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.annotation.DataWarehouseScope;
import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.domain.NccRequestDTO;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.DocConfirmDTO;
import com.bzkj.document.domain.materialout.dto.IcMaterialB;
import com.bzkj.document.domain.materialout.dto.IcMaterialH;
import com.bzkj.document.domain.materialout.dto.IcMaterialRequest;
import com.bzkj.document.domain.materialout.dto.MaterialOutboundDTO;
import com.bzkj.document.domain.materialout.vo.MaterialOutboundBodyVo;
import com.bzkj.document.domain.materialout.vo.MaterialOutboundHeaderVo;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.enums.ProcessingType;
import com.bzkj.document.exception.InventoryException;
import com.bzkj.document.mapper.MaterialOutboundMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.service.materialsoutbound.MaterialOutboundService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.DocumentNoUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.materialout.MaterialOutUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @projectName: prt-wms
 * @package: com.bzkj.document.service.materialsoutbound.impl
 * @className: MaterialOutboundSeriveImpl
 * @description: 材料出库单服务层
 * @author: C1309
 * @createDate: 2024年12月09日
 * @version: v1.0
 */
@Service
public class MaterialOutboundServiceImpl implements MaterialOutboundService {

    /**
     * 固定的 pk_org 值
     */
    private static final String PK_ORG = "111";

    /**
     * NCC接口请求工具
     */
    @Resource
    private NccHttpUtils nccHttpUtils;

    /**
     * 持久层
     */
    @Resource
    private MaterialOutboundMapper materialOutboundMapper;

    @Resource
    private WmsWareHouseInventoryMapper wmsWareHouseInventoryMapper;

    /**
     * 库存管理工具
     */
    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    /**
     * 材料出库单工具
     */
    @Resource
    private MaterialOutUtils materialOutboundUtils;

    /**
     * wms单据号工具
     */
    @Resource
    private DocumentNoUtils documentNoUtils;

    /**
     * 消息提醒构建工具
     */
    @Resource
    private MessageUtil messageUtil;

    /**
     * NCC查询接口地址
     */
    private static final String QUERY_URL = "/nccloud/api/ic/materialout/schemequery";

    /**
     * NCC签字接口地址
     */
    private static final String SIGN_URL = "/nccloud/api/ic/materialout/sign";

    /**
     * NCC修改接口地址
     */
    private static final String UPDATE_URL = "/nccloud/api/ic/materialout/update";

    /**
     * NCC新增接口地址
     */
    private static final String SAVE_URL = "/nccloud/api/ic/materialout/save";

    // ==========================================================
    // 模块名称: 材料出库单NCC查询模块
    // 功能描述: 对NCC材料出库单进行查询操作
    // ==========================================================

    /**
     * 查询NCC材料出库单
     *
     * @param nccRequestDTO 请求参数
     * @return 查询结果
     */
    @Override
    public TableDataInfo selectMaterialOutboundOrder(NccRequestDTO nccRequestDTO) {
        try {

            nccHttpUtils.setWarehouseId(nccRequestDTO, wmsWareHouseInventoryMapper.selectWarehouseId());

            // 发起请求并处理响应
            NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_URL, JSONObject.toJSONString(nccRequestDTO));

            // 校验响应数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析NCC返回的材料出库单数据
            List<Map<String, Object>> dataList = materialOutboundUtils.parsingMaterialOutboundOrders(nccApiResponse, ProcessingType.SELECT_NCC_ORDER.ordinal(), true);

//            if (dataList == null || dataList.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }

            // 返回分页数据
            return DataProcessUtils.startPageInfo(nccRequestDTO.getPageNum(), nccRequestDTO.getPageSize(), dataList);
        } catch (Exception e) {
            // 捕获请求异常并返回具体错误提示
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), e, "查询");
            throw new RuntimeException(errorMessage, e);
        }
    }

    // ==========================================================
    // 模块名称: NCC材料出库单WMS确认模块
    // 功能描述: WMS对NCC材料出库单进行确认操作
    // ==========================================================

    /**
     * 确认NCC材料出库单
     *
     * @param docConfirmDTO 请求参数
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult confirmOutboundOrder(DocConfirmDTO docConfirmDTO) {
        // 提取登录用户信息
        LoginUser loginUser = docConfirmDTO.getLoginUser();
        String billDate = nccHttpUtils.getBillDate(docConfirmDTO.getBillDate());
        List<String> billCodeList = docConfirmDTO.getvBillCodeList();
        int confirmType = docConfirmDTO.getConfirmType() == null ? 1 : docConfirmDTO.getConfirmType();

        // 成功处理的单据列表
        List<String> successList = new ArrayList<>();

        // 逐个处理单据
        for (String billCode : billCodeList) {
            if (isBillExist(billCode)) {
                continue;
            }
            try {
                // 调用 NCC 接口获取物料出库单数据
                List<Map<String, Object>> materialOutboundOrders = fetchMaterialOutboundOrders(billCode, billDate);
                // 处理物料出库单
                String errorMsg = processMaterialOutboundOrders(materialOutboundOrders, loginUser, successList, billCode, confirmType);
                if (errorMsg != null) {
                    String[] split = errorMsg.split("x-x");
                    if (split.length == 2) {
                        if ("1".equals(split[0])) {
                            throw new RuntimeException(split[1]);
                        } else if ("2".equals(split[0])) {
                            return AjaxResult.wmsApiWarning(split[1]);
                        }
                    }
                }
            } catch (Exception e) {
                String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), e, "确认");
                throw new RuntimeException(exceptionMessage, e);
            }
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(successList, DocumentType.MATERIAL_OUTBOUND.getCode(), "确认"));
    }

    /**
     * 检查单据是否已存在
     */
    private boolean isBillExist(String billCode) {
        return materialOutboundMapper.selectIsExist(billCode) > 0;
    }

    /**
     * 调用 NCC 接口获取物料出库单数据
     */
    private List<Map<String, Object>> fetchMaterialOutboundOrders(String billCode, String billDate) throws Exception {

        String getConfirmQuery = nccHttpUtils.getConfirmQuery(billDate, billCode);
        NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_URL, getConfirmQuery);

        // 校验 NCC 返回结果
        DataProcessCommonUtils.validateNccResponse(nccApiResponse);

        // 解析返回结果（1：表示确认操作）
        return materialOutboundUtils.parsingMaterialOutboundOrders(nccApiResponse, ProcessingType.CONFIRM_ORDER.ordinal(), true);
    }

    /**
     * 处理材料出库单数据
     */
    @Transactional(rollbackFor = Exception.class)
    public String processMaterialOutboundOrders(List<Map<String, Object>> materialOutboundOrders, LoginUser loginUser, List<String> successList, String billCode, int confirmType) {
        try {
            for (Map<String, Object> materialOutboundOrder : materialOutboundOrders) {
                // 提取表体信息并校验
                List<Map<String, Object>> detailsList = inventoryManagerUtils.extractDetailsList(materialOutboundOrder, loginUser);
                // 提取表头信息
                Map<String, Object> headerMap = extractHeaderMap(materialOutboundOrder, loginUser);

                String errorMsg = inventoryManagerUtils.checkErrorMsg(detailsList);
                if (errorMsg != null) {
                    return "1x-x" + errorMsg;
                }
                String batchNoError = inventoryManagerUtils.checkBatchNo(detailsList, confirmType, "warehouseout");
                if (batchNoError != null) {
                    return "2x-x" + batchNoError;
                }

                String vtrantypecode = headerMap.get("vtrantypecode").toString();

                // 校验WMS库存并插入明细数据
                int detailsResult = batchInsertDetails(detailsList, vtrantypecode);

                billCode = billCode == null ? (String) headerMap.get("vbillcode") : billCode;

                if (detailsResult == detailsList.size()) {
                    // 插入表头数据
                    int headerResult = materialOutboundMapper.addMaterialOrderHeader(headerMap);
                    if (headerResult > 0) {

                        NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(UPDATE_URL, headerMap.get("cgeneralhid").toString(), "ic_material_h", "Y");
                        if (nccApiResponse.isSuccess()) {
                            successList.add(billCode);
                        } else {
                            throw new RuntimeException("向NCC返回单据同步状态失败，请检查后重试！");
                        }
                    }
                }
            }
            return null;
        } catch (Exception e) {
            throw new RuntimeException("单据处理失败：" + e.getMessage(), e);
        }
    }

    /**
     * 提取并处理表头数据
     */
    private Map<String, Object> extractHeaderMap(Map<String, Object> materialOutboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        Map<String, Object> headerMap = (Map<String, Object>) materialOutboundOrder.get("header");
        String wmsMatOutNo = documentNoUtils.generateMatOrderNumber();
        headerMap.put("vdef49", wmsMatOutNo);
        headerMap.put("vdef50", wmsMatOutNo);
        DataProcessUtils.addHeaderInfo(headerMap, loginUser);
        return headerMap;
    }

    /**
     * 提取并处理明细数据
     */
    private List<Map<String, Object>> extractDetailsList(Map<String, Object> materialOutboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> detailsList = (List<Map<String, Object>>) materialOutboundOrder.get("details");
        for (Map<String, Object> detailMap : detailsList) {
            DataProcessUtils.addDetailInfo(detailMap, loginUser);
        }
        return detailsList;
    }

    /**
     * 批量插入明细数据
     */
    @Transactional(rollbackFor = Exception.class)
    public int batchInsertDetails(List<Map<String, Object>> detailsList, String vtrantypecode) {
        AtomicInteger count = new AtomicInteger();
        // 判断库存量是否充足
        boolean verifyInventoryConfirm = inventoryManagerUtils.verifyInventoryConfirm(detailsList, "warehouseout", vtrantypecode, DocumentType.MATERIAL_OUTBOUND.getCode());
        if (verifyInventoryConfirm) {
            detailsList.forEach(detail -> {
                count.addAndGet(materialOutboundMapper.addMaterialOrderDetails(detail));
            });
        }
        return count.get();
    }

    // ==========================================================
    // 模块名称: WMS对NCC材料出库单新增模块
    // 功能描述: WMS对NCC材料出库单新增操作
    // ==========================================================

    /**
     * 新增材料出库单
     *
     * @param icMaterialRequest 单据数据
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult addMaterialOutboundOrder(IcMaterialRequest icMaterialRequest) {
        // 初始化成功处理列表
        List<String> successList = new ArrayList<>();

        // 提取登录用户信息、头信息和明细信息
        LoginUser loginUser = icMaterialRequest.getLoginUser();
        IcMaterialH icMaterialH = icMaterialRequest.getIcMaterialH();
        List<IcMaterialB> icMaterialB = icMaterialRequest.getIcMaterialB();

        // 校验请求参数
        if (icMaterialH == null) {
            return AjaxResult.warn("小提示：材料出库单据头信息缺失，请确认提交的请求格式是否正确！");
        }
        if (icMaterialB == null || icMaterialB.isEmpty()) {
            return AjaxResult.warn("注意：未提供任何材料出库单明细信息");
        }

        // 校验库存是否满足出库条件

        // 将请求对象转为 JSON 格式
        String jsonString = JSONObject.toJSONString(icMaterialRequest);

        try {
            // 调用 NCC 接口并获取返回结果
            NccApiResponse nccApiResponse = nccHttpUtils.post(SAVE_URL, "[" + jsonString + "]");

            // 校验 NCC 返回结果
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析返回数据
            List<Map<String, Object>> materialOutboundOrders = materialOutboundUtils.parsingMaterialOutboundOrders(nccApiResponse, icMaterialB, true);

            if (materialOutboundOrders == null) {
                return AjaxResult.warn("注意：NCC未返回任何数据！");
            }

            // 处理材料出库单
            processMaterialOutboundOrders(materialOutboundOrders, loginUser, successList, null, 1);

        } catch (Exception e) {
            // 统一异常处理并抛出运行时异常
            String exceptionMessage = messageUtil.operateExceptionMessage(
                    DocumentType.MATERIAL_OUTBOUND.getCode(), e, "新增"
            );
            throw new RuntimeException(exceptionMessage, e);
        }

        // 返回操作成功结果
        return AjaxResult.success(
                messageUtil.operateSuccessMessage(successList, DocumentType.MATERIAL_OUTBOUND.getCode(), "新增")
        );
    }

    // ==========================================================
    // 模块名称: 查询WMS材料出库单模块
    // 功能描述: 查询WMS材料出库单
    // ==========================================================

    /**
     * 查询本地已经确认的材料出库单据
     *
     * @param materialOutboundDTO 查询条件
     * @param pageNum             页码
     * @param pageSize            页面大小
     * @return 查询结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DataWarehouseScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo selectLocalMaterialOutboundOrder(MaterialOutboundDTO materialOutboundDTO, int pageNum, int pageSize) {
        // 处理日期范围过滤条件
        DataProcessUtils.handleDateRange(materialOutboundDTO);

        // 处理单据状态过滤条件
        String originalBillsState = Optional.ofNullable(materialOutboundDTO.getBillsState())
                .filter(state -> !state.isEmpty())
                .orElse(null);

        // For header query, we modify state 4/5 to 3
        String headerQueryBillsState = originalBillsState != null
                ? (originalBillsState.equals("4") || originalBillsState.equals("5") ? "3" : originalBillsState)
                : null;
        materialOutboundDTO.setBillsState(headerQueryBillsState);
        // 查询表头数据
        List<MaterialOutboundHeaderVo> outboundHeadVOList = materialOutboundMapper.selectLocalMaterialOutboundOrderHeader(materialOutboundDTO);
        if (outboundHeadVOList.isEmpty()) {
            return DataProcessCommonUtils.getTableInfo(Collections.emptyList(), pageNum, pageSize);
        }

        // 获取物料过滤条件
        String filterMaterialOid = Optional.ofNullable(materialOutboundDTO.getMaterial()).orElse("");
        boolean shouldFilterByMaterial = !filterMaterialOid.isEmpty();
        boolean shouldFilterBySkuState = originalBillsState != null
                && (originalBillsState.equals("4") || originalBillsState.equals("5"));
        List<HashMap<String, Object>> responseDataList = outboundHeadVOList.parallelStream().map(headVO -> {
                    // 查询对应单据明细
                    List<MaterialOutboundBodyVo> materialOutboundBodyVos = materialOutboundMapper.queryMaterialOrderDetails(
                            headVO.getCgeneralhid(),
                            headerQueryBillsState);
                    if (materialOutboundBodyVos == null || materialOutboundBodyVos.isEmpty()) {
                        return null;
                    }
                    // 应用过滤条件
                    if (shouldFilterByMaterial && materialOutboundBodyVos.stream()
                            .noneMatch(body -> filterMaterialOid.equals(body.getCmaterialoid().getPk()))) {
                        return null;
                    }
                    if (shouldFilterBySkuState && materialOutboundBodyVos.stream().noneMatch(body -> originalBillsState.equals(body.getSkuState()))) {
                        return null;
                    }
                    // 构建结果
                    HashMap<String, Object> result = new HashMap<>(2);
                    result.put("header", headVO);
                    result.put("details", materialOutboundBodyVos);
                    return result;
                }).filter(Objects::nonNull)
                .collect(Collectors.toList());
        return DataProcessCommonUtils.getTableInfo(responseDataList, pageNum, pageSize);
    }

    /**
     * 材料出库单回退至未提取状态
     *
     * @param headerId  单据表头主键
     * @param loginUser 登录用户信息
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult orderBack(String headerId, LoginUser loginUser) {
        HashMap<String, String> billStatusMap = materialOutboundMapper.getBillStatus(headerId);
        String billState = billStatusMap.get("billState");
        String vbillCode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.cancelExtractBillMessage(billState, DocumentType.MATERIAL_OUTBOUND.getDescription());
        return ajaxResult.isSuccess() ? processOrderBack(headerId, loginUser, vbillCode) : ajaxResult;
    }

    private AjaxResult processOrderBack(String headerId, LoginUser loginUser, String vbillCode) {
        // 撤回材料出库单表头
        int i = materialOutboundMapper.orderBackHead(headerId, loginUser.getUserId().toString());
        if (i > 0) {
            // 撤回材料出库单表体
            int i1 = materialOutboundMapper.orderBackDetails(headerId, loginUser.getUserId().toString());
            if (i1 > 0) {
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillCode), DocumentType.MATERIAL_OUTBOUND.getCode(), "取消提取"));
            }
        }
        return AjaxResult.error("系统出现未知错误，请联系系统管理员处理！");
    }

    // ==========================================================
    // 模块名称: NCC材料出库单修改模块
    // 功能描述: 对NCC采购入库单进行修改操作
    // ==========================================================

    /**
     * 修改材料出库单
     *
     * @param responseBody 请求参数
     * @param loginUser    登录用户信息
     * @param isSign       是否跳过校验
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updateMaterialOutBoundOrder(HashMap<String, Object> responseBody, LoginUser loginUser, boolean isSign) {
        String vbillcode;
        try {
            // 提取并校验头信息
            HashMap<String, Object> headerMap = extractHeaderInfo(responseBody);
            String cgeneralhid = headerMap.get("cgeneralhid").toString();

            // 校验单据状态
            if (!isSign) {
                AjaxResult validationResult = validateBillStatus(cgeneralhid);
                if (!validationResult.isSuccess()) {
                    return validationResult;
                }
            }

            // 封装 NCC 请求参数
            HashMap<String, Object> nccRequestMap = prepareNccRequest(responseBody);
            JSONObject jsonObject = new JSONObject(nccRequestMap);
            JSONObject icMaterialH = jsonObject.getJSONObject("ic_material_h");
            if (icMaterialH.get("cwarehouseid") != null){
                icMaterialH.remove("cwarehouseid");
            }

            // 调用 NCC 接口并校验返回结果
            NccApiResponse nccApiResponse = nccHttpUtils.post(UPDATE_URL, jsonObject.toJSONString());

            // 校验NCC返回的结果
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析和处理返回数据,2表示修改
            List<Map<String, Object>> materialOutboundOrders = materialOutboundUtils.parsingMaterialOutboundOrders(nccApiResponse, ProcessingType.UPDATE_NCC_ORDER.ordinal(), false);


            vbillcode = processOutboundOrders(materialOutboundOrders, loginUser);

        } catch (Exception e) {
            String exceptionMessage;
            if (!isSign) {
                exceptionMessage = messageUtil.operateExceptionMessage(
                        DocumentType.MATERIAL_OUTBOUND.getCode(), e, "修改"
                );
            } else {
                return AjaxResult.error(messageUtil.operateExceptionMessage(
                        DocumentType.MATERIAL_OUTBOUND.getCode(), e, "签字"));
            }
            throw new RuntimeException(exceptionMessage, e);
        }

        // 返回成功结果
        return AjaxResult.success(
                messageUtil.operateSuccessMessage(
                        Collections.singletonList(vbillcode),
                        DocumentType.MATERIAL_OUTBOUND.getCode(),
                        "修改"
                )
        );
    }

    /**
     * 提取头信息并校验
     */
    private HashMap<String, Object> extractHeaderInfo(HashMap<String, Object> responseBody) {
        @SuppressWarnings("unchecked")
        HashMap<String, Object> headerMap = (HashMap<String, Object>) responseBody.get("ic_material_h");
        if (headerMap == null || !headerMap.containsKey("cgeneralhid")) {
            throw new IllegalArgumentException("提示：单据头信息缺失或不完整！");
        }
        return headerMap;
    }

    /**
     * 校验单据状态
     */
    private AjaxResult validateBillStatus(String cgeneralhid) {
        HashMap<String, String> billInfoMap = materialOutboundMapper.getBillStatus(cgeneralhid);
        String billState = billInfoMap.get("billState");
        return messageUtil.updateBillMessage(billState, DocumentType.MATERIAL_OUTBOUND.getDescription());
    }

    /**
     * 封装 NCC 请求参数
     */
    private HashMap<String, Object> prepareNccRequest(HashMap<String, Object> responseBody) {
        HashMap<String, Object> nccRequestMap = new HashMap<>(2);
        nccRequestMap.put("ic_material_h", responseBody.get("ic_material_h"));
        nccRequestMap.put("ic_material_b", responseBody.get("ic_material_b"));
        return nccRequestMap;
    }

    /**
     * 处理材料出库单
     */
    private String processOutboundOrders(List<Map<String, Object>> materialOutboundOrders, LoginUser loginUser) {
        String vbillcode = "";
        for (Map<String, Object> materialOutboundOrder : materialOutboundOrders) {
            @SuppressWarnings("unchecked")
            Map<String, Object> headerInfoMap = (Map<String, Object>) materialOutboundOrder.get("header");
            vbillcode = headerInfoMap.get("vbillcode").toString();
            DataProcessUtils.updateInfo(headerInfoMap, loginUser);

            // 修改表头数据
            int resultNum = materialOutboundMapper.updateMaterialOutboundOrder(headerInfoMap);
            if (resultNum <= 0) {
                throw new RuntimeException("表头数据更新失败！");
            }

            // 修改表体数据
            @SuppressWarnings("unchecked")
            List<HashMap<String, Object>> detailsList =
                    (List<HashMap<String, Object>>) materialOutboundOrder.get("details");
            int count = updateOrderDetails(detailsList, loginUser);
            if (count != detailsList.size()) {
                String failureMessage = messageUtil.documentFailureMessage(
                        Collections.singletonList(headerInfoMap.get("vbillcode").toString()),
                        DocumentType.MATERIAL_OUTBOUND.getCode(),
                        "修改",
                        "明细"
                );
                throw new RuntimeException(failureMessage);
            }
        }
        return vbillcode;
    }

    /**
     * 更新表体数据
     */
    private int updateOrderDetails(List<HashMap<String, Object>> detailsList, LoginUser loginUser) {
        int count = 0;
        for (HashMap<String, Object> detailMap : detailsList) {
            DataProcessUtils.updateInfo(detailMap, loginUser);
            count += materialOutboundMapper.updateMaterialOutboundOrderDetails(detailMap);
        }
        return count;
    }


    // ==========================================================
    // 模块名称: NCC材料出库单签字模块
    // 功能描述: 对NCC采购入库单进行签字操作
    // ==========================================================

    /**
     * 材料出库单签字
     *
     * @param cgeneralhid 表头主键
     * @param loginUser   登录用户
     * @return 结果
     */
    @Override
    public AjaxResult signatureMaterialOutBound(String cgeneralhid, LoginUser loginUser) {
        // 参数校验：请求参数是否为空，headerId是否存在
        if (cgeneralhid == null || cgeneralhid.isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), "签字"));
        }

        // 获取当前单据状态
        Map<String, String> billStateMap = materialOutboundMapper.getBillStatus(cgeneralhid);
        String billStatus = billStateMap.get("billState");
        String billCode = billStateMap.get("vbillcode");

        // 根据单据状态返回消息
        AjaxResult ajaxResult = messageUtil.signedBillMessage(billStatus, DocumentType.MATERIAL_OUTBOUND.getDescription());
        return ajaxResult.isSuccess() ? processSignBill(cgeneralhid, billCode, loginUser) : ajaxResult;
    }

    /**
     * 对已完成的单据进行签字处理
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @return 结果
     */
    private AjaxResult processSignBill(String cgeneralhid, String vBillCode, LoginUser loginUser) {
        try {
            // 准备表头数据并提取“vtrantypecode”
            HashMap<String, Object> headerMap = prepareHeaderData(cgeneralhid);
            String vtrantypecode = headerMap.get("vtrantypecode").toString();
            // 校验并准备明细数据
            List<HashMap<String, Object>> detailList = prepareDetails(cgeneralhid, vtrantypecode);
            if (detailList.isEmpty()) {
                return AjaxResult.error(messageUtil.updateDocumentZeroQuantityMessage(DocumentType.MATERIAL_OUTBOUND.getCode()));
            }
            // 更新采购单
            AjaxResult updateResult = updateMaterialOrder(headerMap, detailList, loginUser);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }
            // 调用外部接口并更新状态
            return handleExternalApiAndInventory(cgeneralhid, vBillCode, loginUser, detailList.size());
        } catch (Exception e) {
//            logError("采购入库单签字异常", e); // 记录异常日志
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), e, "签字");
            throw new RuntimeException(exceptionMessage, e);
        }
    }

    /**
     * 校验并准备明细数据
     *
     * @param cgeneralhid   单据号主键
     * @param vtrantypecode 单据类型
     * @return 明细列表或null（校验失败）
     */
    private List<HashMap<String, Object>> prepareDetails(String cgeneralhid, String vtrantypecode) {
        // 查询单据明细信息
        List<MaterialOutboundBodyVo> details = materialOutboundMapper.queryMaterialOrderDetails(cgeneralhid, null);
        // 构建更新明细列表
        List<HashMap<String, Object>> detailList = new ArrayList<>();
        // 校验库存是否充足
        boolean verifyInventory = inventoryManagerUtils.verifyInventorySign(details, "warehouseout", vtrantypecode, DocumentType.MATERIAL_OUTBOUND.getCode());
        if (verifyInventory) {
            for (MaterialOutboundBodyVo detail : details) {
                HashMap<String, Object> detailMap = new HashMap<>();
                detailMap.put("cgeneralbid", detail.getCgeneralbid());
                detailMap.put("nnum", detail.getNnum());
                detailList.add(detailMap);
            }
        }
        return detailList;
    }


    /**
     * 准备表头数据
     *
     * @param cgeneralhid 表头主键
     * @return 表头数据
     */
    private HashMap<String, Object> prepareHeaderData(String cgeneralhid) {
        MaterialOutboundHeaderVo materialOutboundHeaderVo = materialOutboundMapper.selectLocalMaterialOutboundOrderHeaderByBillCode(cgeneralhid);
        if (materialOutboundHeaderVo == null) {
            throw new IllegalStateException("材料出库单表头信息不存在！");
        }

        HashMap<String, Object> headerMap = new HashMap<>();
        headerMap.put("cgeneralhid", materialOutboundHeaderVo.getCgeneralhid());
        headerMap.put("vtrantypecode", materialOutboundHeaderVo.getVtrantypecode());
        return headerMap;
    }

    /**
     * 更新材料出库单
     *
     * @param headerMap  表头数据
     * @param detailList 明细列表
     * @param loginUser  登录用户
     * @return 更新结果
     */
    private AjaxResult updateMaterialOrder(HashMap<String, Object> headerMap, List<HashMap<String, Object>> detailList, LoginUser loginUser) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("ic_material_h", headerMap);
        resultMap.put("ic_material_b", detailList);
        return updateMaterialOutBoundOrder(resultMap, loginUser, true);
    }

    /**
     * 处理外部接口调用和库存更新
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @param detailSize  明细数量
     * @return 结果
     */
    private AjaxResult handleExternalApiAndInventory(String cgeneralhid, String vBillCode, LoginUser loginUser, int detailSize) throws IOException {
        // 调用外部接口
        NccApiResponse apiResponse = nccHttpUtils.post(SIGN_URL, "[" + cgeneralhid + "]");

        // 校验NCC响应
        DataProcessCommonUtils.validateNccResponse(apiResponse);

        // 更新单据状态
        materialOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), null);

        // 更新库存管理
        Integer rowCount = inventoryManagerUtils.wmsWarehouseOut(vBillCode, "MaterialWareHouseOut");
        if (rowCount != null && detailSize == rowCount) {
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vBillCode), DocumentType.MATERIAL_OUTBOUND.getCode(), "签字"));
        } else {
            materialOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.WMS_FAILURE_CODE, loginUser.getUsername(), null);
            return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.MATERIAL_OUTBOUND.getCode()));
        }
    }

    /**
     * 更新库存
     *
     * @param cgeneralhid 表头主键
     * @param loginUser   登录用户
     * @return 操作结果
     */
    @Override
    public AjaxResult updateInventory(String cgeneralhid, LoginUser loginUser) {
        try {
            // 获取表头
            MaterialOutboundHeaderVo materialOutboundHeaderVo = materialOutboundMapper.selectLocalMaterialOutboundOrderHeaderByBillCode(cgeneralhid);

            // 获取明细
            List<MaterialOutboundBodyVo> details = materialOutboundMapper.queryMaterialOrderDetails(cgeneralhid, null);

            // 检查库存是否充足
//            checkInventory(details, materialOutboundHeaderVo);
            inventoryManagerUtils.verifyInventorySign(details, "warehouseout", materialOutboundHeaderVo.getVtrantypecode(), DocumentType.MATERIAL_OUTBOUND.getCode());
            // 执行出库操作
            Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(materialOutboundHeaderVo.getVbillcode(), "MaterialWareHouseOut");

            // 更新单据状态
            updateBillState(cgeneralhid, loginUser, rowCount, details.size());

            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(materialOutboundHeaderVo.getVbillcode()), DocumentType.MATERIAL_OUTBOUND.getCode(), "签字"));
        } catch (InventoryException e) {
//            log.error("库存检查失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
//            log.error("更新库存失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        }

    }

    /**
     * 检查库存是否充足
     *
     * @param details                  明细信息
     * @param materialOutboundHeaderVo 表头信息
     * @throws InventoryException 库存异常
     */
    private void checkInventory(List<MaterialOutboundBodyVo> details, MaterialOutboundHeaderVo materialOutboundHeaderVo) throws InventoryException {
        for (MaterialOutboundBodyVo detail : details) {
            if (detail.getNshouldnum() > 0) {
                int resultType = inventoryManagerUtils.isEnough(
                        detail.getVbillcode(),
                        materialOutboundHeaderVo.getVtrantypecode(),
                        detail.getCmaterialvid().getPk(),
                        detail.getVbatchcode(),
                        detail.getNnum(),
                        "2",
                        detail.getCstateid(), "", "");
                if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "库存可用量不足！");
                } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "当前商品不支持在此单据类型下使用！");
                }
            }
        }
    }

    /**
     * 更新单据状态
     *
     * @param cgeneralhid 单据主键
     * @param loginUser   登录用户
     * @param rowCount    入库数量
     * @param detailSize  明细数量
     */
    private void updateBillState(String cgeneralhid, LoginUser loginUser, Integer rowCount, int detailSize) {
        // 判断入库明细是否与单据明细数量相等
        if (rowCount != null && detailSize == rowCount) {
            materialOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), null);
        } else {
            throw new RuntimeException(messageUtil.updateDocumentWmsFailureMessage(DocumentType.MATERIAL_OUTBOUND.getCode()));
        }
    }

    /**
     * 删除材料出库单
     *
     * @param cgeneralhid 表头主键
     * @param loginUser   登录用户
     * @param reason      作废原因
     * @return 操作结果
     */
    @Override
    public AjaxResult deleteMaterialOutboundOrder(String cgeneralhid, LoginUser loginUser, String reason) {

        if (cgeneralhid == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } else if (cgeneralhid.trim().isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), BusinessType.INVALID.getDescription()));
        }
        // 获取当前单据状态
        HashMap<String, String> billStateMap = materialOutboundMapper.getBillStatus(cgeneralhid);
        String billStatus = billStateMap.get("billState");
        String vbillcode = billStateMap.get("vbillcode");

        // 调用消息工具（根据不同的单据状态返回不同的消息）
        AjaxResult ajaxResult = messageUtil.deleteBillMessage(billStatus, DocumentType.MATERIAL_OUTBOUND.getDescription());

        return ajaxResult.isSuccess() ? handleDeleteBill(cgeneralhid, vbillcode, loginUser, reason) : ajaxResult;
    }

    /**
     * 作废材料出库单
     *
     * @param cgeneralhid 表头主键
     * @param vbillcode   单据号
     * @param loginUser   登录用户
     * @param reason      作废原因
     * @return 操作结果
     */
    private AjaxResult handleDeleteBill(String cgeneralhid, String vbillcode, LoginUser loginUser, String reason) {
        try {
            // 调用删除接口
            NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(UPDATE_URL, cgeneralhid, "ic_material_h", "");
            // 校验NCC返回的数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            materialOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.DELETED_CODE, loginUser.getUsername(), reason);
            // 校验NCC响应
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.MATERIAL_OUTBOUND.getCode(), BusinessType.INVALID.getDescription()));

        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.MATERIAL_OUTBOUND.getCode(), e, BusinessType.INVALID.getDescription());
            //            log.error("采购入库单修改异常: ", e);
            throw new RuntimeException(errorMessage, e);
        }
    }
}
